-- BossTentM
-- Created by dengc Jul/6/2016
-- Boss层的流浪者帐篷

module("BossTentM", package.seeall);

-- 流浪者刷新所需回合数
local INTERVAL_ROUND = 5;

-- 当前最多可同时存在的流浪者数量
local MAX_TRAMP_NUM = 4;

-- 左边帐篷的位置
local LEFT_TENT_POS = 11;

-- 右边帐篷的位置
local RIGHT_TENT_POS = 15;

-- 刷怪帐篷的集合
local tentPosList = {LEFT_TENT_POS, RIGHT_TENT_POS};

-- 允许刷出流浪者的位置集合
local trampPosList = {16, 20, 21, 25};

-- 左侧帐篷的刷怪CD顺序
local leftCdList = {1, 5, 4, 3, 2};

-- 右侧帐篷的刷怪CD顺序
local rightCdList = {3, 2, 1, 5, 4};

-- 当前层存在的流浪者的数量
local curTrampNum = 0;

-- 当前刷怪的帐篷位置
local curTentPos = LEFT_TENT_POS;

-- 内部函数
local whenLeaveDungeon;
local whenNextFloor;
local whenCombatRound;

-- 初始化
function init()
    -- 关注回合数变化
    EventMgr.removeAll("BossTentM");

    CombatM.registerStartRoundCB("boss_tent_start_round", whenCombatRound);

    -- 关注玩家离开地牢的事件
    EventMgr.register("BossTentM", event.LEAVE_DUNGEON, function()
        whenLeaveDungeon();
    end);

    -- 关注进入下一层的事件
    EventMgr.register("BossTentM", event.NEXT_FLOOR, function()
        whenNextFloor();
    end);

    -- 关注层数回退（大地之门等技能）的事件
    EventMgr.register("BossTentM", event.BACK_FLOOR, function()
        whenNextFloor();
    end);
end

-- 回合数变化
function whenCombatRound()
    -- 只处理在Boss层的情况
    if not DungeonBossM.isInBossLayer() then
        return;
    end

    -- 更新已刷成的数量
    updateTrampNum();

    -- 尝试刷出流浪者
    for _, pos in pairs(tentPosList) do
        refreshTramp(pos);
    end
end

-- 关注玩家离开地牢的事件
function whenLeaveDungeon()
    curTrampNum = 0;
end

-- 进入下一层的回调
function whenNextFloor()
    curTrampNum = 0;
end

-- 获取帐篷刷怪轮次倒计时
function getRefreshCountDown(pos)
    -- 如果格子无效了，那么就不再刷了
    local grid = DungeonM.getGridByPos(pos);
    if grid.state == GRID_STATE_DISABLE then
        return -1;
    end

    -- 左侧的初始CD为1，右侧的初始CD为3
    local tentRound = CombatM.getRound();
    local round = tentRound % INTERVAL_ROUND;
    round = (round == 0) and INTERVAL_ROUND or round;
    if pos == RIGHT_TENT_POS then
        return rightCdList[round];
    else
        return leftCdList[round];
    end
end

-- 当前位置是否是流浪者帐篷
-- 是的话，返回当前格子对象
function isTentGrid(pos)
    local grid = DungeonM.getGridByPos(pos);

    if grid.state ~= GRID_STATE_DISABLE and
        grid.type == GRID_TYPE_INSTANCE and
        isTentInstance(grid.instanceId) then
        return grid;
    end
end

-- 判断该副本是否是流浪者帐篷
function isTentInstance(instanceId)
    local instanceInfo = DungeonInstanceM.getInstanceInfo(instanceId);
    if not instanceInfo then
        return false;
    end

    return instanceInfo["type"] == INSTANCE_TYPE_TENT;
end

-- 是否存在已失效的格子
function isInvalidGridExists()
    return curTrampNum < MAX_TRAMP_NUM;
end

-- 获取允许刷怪格子
function getTrampGrid()
    local trampGrids = {};
    for _, pos in pairs(trampPosList) do
        table.insert(trampGrids, DungeonM.getGridByPos(pos));
    end
    return trampGrids;
end

-- 查找已失效的格子（包含空格）
-- 如果存在多个，随机返回一个，否则返回nil
function findInvalidGrid()
    local gridList = {};
    local trampGrids = getTrampGrid();
    for _, grid in pairs(trampGrids) do
        if grid and (not grid.monster or grid.monster:isDead()) then
            table.insert(gridList, grid);
        end
    end

    local gridCount = #gridList;
    if gridCount == 0 then
        return nil;
    end

    if gridCount == 1 then
        return gridList[1];
    end

    -- 存在多个，随机返回一个
    local randSeed = DungeonM.getRandSeed("tent_find_invalid_grid");
    local index = randSeed % gridCount + 1;

    -- 根据位置排序
    table.sort(gridList, function(grid1, grid2) return grid1:getPos() < grid2:getPos(); end);

    return gridList[index];
end

-- 是否刷出流浪者
function isRefreshTramp(pos)
    local tentGrid = isTentGrid(pos);
    if not tentGrid then
        -- 流浪者帐篷格子不存在
        return false;
    end

    -- 判断回合数
    if getRefreshCountDown(pos) % INTERVAL_ROUND ~= 1 then
        return false;
    end

    -- 是否存在已失效的格子
    if not isInvalidGridExists() then
        -- 没有已失效的格子
        DungeonLogM.addLog("[BossTentM]没有失效的格子，不刷新流浪者。");
        return false;
    end

    -- 判断已刷出的数量
    if true == isRefreshNumLimit() then
        -- 数量已达上限
        trace("BossTentM", "流浪者刷新数量已达上限。");
        return false;
    end

    -- 玩家使用了时间停止
    local prop = PropM.combine(ME.user, "stop_action", 1);
    if PropM.apply(prop, 1) > 0 then
        -- 玩家使用了时间停止
        trace("BossTentM", "玩家使用了时间停止。");
        return false;
    end

    return true;
end

-- 刷怪数量是否已达上限
function isRefreshNumLimit()
    return curTrampNum >= MAX_TRAMP_NUM;
end

-- 刷出流浪者
function refreshTramp(pos)
    if not isRefreshTramp(pos) then
        return false;
    end

    local msg = string.format("[BossTentM]流浪者帐篷回合数更新至：%d", CombatM.getRound());
    DungeonLogM.addLog(msg);

    -- 随机选择一个已失效的格子
    local grid = findInvalidGrid();
    if not grid then
        return false;
    end

    -- 抽取流浪者
    local element = fetchTramp(pos);
    if not element then
        trace("BossTentM", "抽取流浪者失败了。");
        return false;
    end

    -- 将格子刷成怪
    local transPos = grid:getPos();
    DungeonM.transGridToMonster(transPos, element, "tent");

    -- 更新下当前存在的流浪者数量
    updateTrampNum();

    -- 记录下当前刷怪的帐篷
    curTentPos = pos;
    trace("BossTentM", "刷出流浪者的帐篷：%d", pos);

    local msg = string.format("[BossTentM]格子%d刷出第%d个流浪者(element = %d)", transPos, curTrampNum, element);
    DungeonLogM.addLog(msg);

    -- 抛出帐篷刷怪事件
    EventMgr.fire(event.TENT_REFRESH_MONSTER, { ["element"] = element, });

    return true;
end

-- 更新当前BOSS层流浪者的数量
function updateTrampNum()
    -- 找下是否存在流浪者帐篷
    for _, pos in pairs(tentPosList) do
        if not isTentGrid(pos) then
            return;
        end
    end

    -- 刷新下数量
    local num = 0;
    local trampGrids = getTrampGrid();
    for _, grid in pairs(trampGrids) do
        if grid.monster and not grid.monster:isDead() then
            num = num + 1;
        end
    end
    curTrampNum = num;
end

-- 抽取一个流浪者
function fetchTramp(pos)
    local grid = isTentGrid(pos);
    if not grid then
        -- 流浪者帐篷格子未刷出
        return nil;
    end

    local instanceId = grid.instanceId;
    local instanceInfo = DungeonInstanceM.getInstanceInfo(instanceId);
    if not instanceInfo then
        return nil;
    end

    local dungeonId = instanceInfo["dungeon_id"];
    local elements = DungeonM.getElementsByDungeon(dungeonId);
    if not elements then
        -- 该副本没有配置元素？
        return nil;
    end

    local class = DungeonM.getClassByType(GRID_TYPE_MONSTER, "monster");
    if not elements[class] then
        -- 该副本没有配置怪物？
        return nil;
    end

    local seed = DungeonM.getRandSeed("fetch_tramp");

    -- 根据权重抽取一个怪物
    local ret = fetchElemBySeed(elements[class], seed);

    return ret["id"];
end

-- 获得当前刷怪的帐篷
function getCurTentPos()
    return curTentPos;
end

-- 当前层是否存在BOSS层的流浪者帐篷
function isHaveBossTent()
    if not DungeonBossM.isInBossLayer() then
        return false;
    end

    for _, pos in pairs(tentPosList) do
        if isTentGrid(pos) then
            return true;
        end
    end
    return false;
end

-- 获取流浪者帐篷的位置
function getTentPosList()
    return tentPosList;
end

-- 当前位置是否是刷流浪者的位置
function isTrampPos(pos)
    -- 没有BOSS层的帐篷
    if not isHaveBossTent() then
        return false;
    end

    for _, trampPos in pairs(trampPosList) do
        if trampPos == pos then
            return true;
        end
    end
    return false;
end

-- 获取允许刷流浪者的位置
function getCanRefreshPos()
    return trampPosList;
end
